<!DOCTYPE html>
<html lang="zh-CN">
    <head>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <meta name="robots" content="noodp" />
        <meta http-equiv="X-UA-Compatible" content="IE=edge, chrome=1">
        <title>Makefile - wuzp blog</title><meta name="Description" content="码农"><meta property="og:title" content="Makefile" />
<meta property="og:description" content="工作方式 GNU的make工作时的执行步骤如下： 读入所有的Makefile. 读入被include的其他Makefile 初始化文件中的变量 推导隐" />
<meta property="og:type" content="article" />
<meta property="og:url" content="https://wuzpdev.gitee.io/makefile/" /><meta property="og:image" content="https://wuzpdev.gitee.io/logo.png"/><meta property="article:section" content="posts" />
<meta property="article:published_time" content="2022-01-25T14:47:44+08:00" />
<meta property="article:modified_time" content="2022-01-25T14:47:44+08:00" />

<meta name="twitter:card" content="summary_large_image"/>
<meta name="twitter:image" content="https://wuzpdev.gitee.io/logo.png"/>

<meta name="twitter:title" content="Makefile"/>
<meta name="twitter:description" content="工作方式 GNU的make工作时的执行步骤如下： 读入所有的Makefile. 读入被include的其他Makefile 初始化文件中的变量 推导隐"/>
<meta name="application-name" content="wuzp blog">
<meta name="apple-mobile-web-app-title" content="wuzp blog"><meta name="theme-color" content="#ffffff"><meta name="msapplication-TileColor" content="#da532c"><link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
        <link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png">
        <link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png"><link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png"><link rel="mask-icon" href="/safari-pinned-tab.svg" color="#5bbad5"><link rel="manifest" href="/site.webmanifest"><link rel="canonical" href="https://wuzpdev.gitee.io/makefile/" /><link rel="prev" href="https://wuzpdev.gitee.io/cmake/" /><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/normalize.css@8.0.1/normalize.min.css"><link rel="stylesheet" href="/css/style.min.css"><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fortawesome/fontawesome-free@5.13.0/css/all.min.css"><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/animate.css@3.7.2/animate.min.css"><script type="application/ld+json">
    {
        "@context": "http://schema.org",
        "@type": "BlogPosting",
        "headline": "Makefile",
        "inLanguage": "zh-CN",
        "mainEntityOfPage": {
            "@type": "WebPage",
            "@id": "https:\/\/wuzpdev.gitee.io\/makefile\/"
        },"image": [{
                            "@type": "ImageObject",
                            "url": "https:\/\/wuzpdev.gitee.io\/images\/Apple-Devices-Preview.png",
                            "width":  3200 ,
                            "height":  2048 
                        }],"genre": "posts","keywords": "makefile","wordcount":  7281 ,
        "url": "https:\/\/wuzpdev.gitee.io\/makefile\/","datePublished": "2022-01-25T14:47:44+08:00","dateModified": "2022-01-25T14:47:44+08:00","license": "This work is licensed under a Creative Commons Attribution-NonCommercial 4.0 International License.","publisher": {
            "@type": "Organization",
            "name": "xxxx","logo": {
                    "@type": "ImageObject",
                    "url": "https:\/\/wuzpdev.gitee.io\/images\/avatar.png",
                    "width":  528 ,
                    "height":  560 
                }},"author": {
                "@type": "Person",
                "name": "wuzp"
            },"description": ""
    }
    </script></head>
    <body header-desktop="fixed" header-mobile="auto"><script type="text/javascript">(window.localStorage && localStorage.getItem('theme') ? localStorage.getItem('theme') === 'dark' : ('auto' === 'auto' ? window.matchMedia('(prefers-color-scheme: dark)').matches : 'auto' === 'dark')) && document.body.setAttribute('theme', 'dark');</script>

        <div id="mask"></div><div class="wrapper"><header class="desktop" id="header-desktop">
    <div class="header-wrapper">
        <div class="header-title">
            <a href="/" title="wuzp blog"><span class="header-title-pre"><i class='far fa-kiss-wink-heart fa-fw'></i></span>wuzp blog</a>
        </div>
        <div class="menu">
            <div class="menu-inner"><a class="menu-item" href="/posts/"> 所有文章 </a><a class="menu-item" href="/tags/"> 标签 </a><a class="menu-item" href="/categories/"> 分类 </a><a class="menu-item" href="/categories/documentation/"> 文档 </a><a class="menu-item" href="/about/"> 关于 </a><a class="menu-item" href="https://gitee.com/wuzpdev" title="Gitee" rel="noopener noreffer" target="_blank"><i class='fab fa-github fa-fw'></i>  </a><span class="menu-item delimiter"></span><span class="menu-item search" id="search-desktop">
                        <input type="text" placeholder="搜索文章标题或内容..." id="search-input-desktop">
                        <a href="javascript:void(0);" class="search-button search-toggle" id="search-toggle-desktop" title="搜索">
                            <i class="fas fa-search fa-fw"></i>
                        </a>
                        <a href="javascript:void(0);" class="search-button search-clear" id="search-clear-desktop" title="清空">
                            <i class="fas fa-times-circle fa-fw"></i>
                        </a>
                        <span class="search-button search-loading" id="search-loading-desktop">
                            <i class="fas fa-spinner fa-fw fa-spin"></i>
                        </span>
                    </span><a href="javascript:void(0);" class="menu-item theme-switch" title="切换主题">
                    <i class="fas fa-adjust fa-fw"></i>
                </a>
            </div>
        </div>
    </div>
</header><header class="mobile" id="header-mobile">
    <div class="header-container">
        <div class="header-wrapper">
            <div class="header-title">
                <a href="/" title="wuzp blog"><span class="header-title-pre"><i class='far fa-kiss-wink-heart fa-fw'></i></span>wuzp blog</a>
            </div>
            <div class="menu-toggle" id="menu-toggle-mobile">
                <span></span><span></span><span></span>
            </div>
        </div>
        <div class="menu" id="menu-mobile"><div class="search-wrapper">
                    <div class="search mobile" id="search-mobile">
                        <input type="text" placeholder="搜索文章标题或内容..." id="search-input-mobile">
                        <a href="javascript:void(0);" class="search-button search-toggle" id="search-toggle-mobile" title="搜索">
                            <i class="fas fa-search fa-fw"></i>
                        </a>
                        <a href="javascript:void(0);" class="search-button search-clear" id="search-clear-mobile" title="清空">
                            <i class="fas fa-times-circle fa-fw"></i>
                        </a>
                        <span class="search-button search-loading" id="search-loading-mobile">
                            <i class="fas fa-spinner fa-fw fa-spin"></i>
                        </span>
                    </div>
                    <a href="javascript:void(0);" class="search-cancel" id="search-cancel-mobile">
                        取消
                    </a>
                </div><a class="menu-item" href="/posts/" title="">所有文章</a><a class="menu-item" href="/tags/" title="">标签</a><a class="menu-item" href="/categories/" title="">分类</a><a class="menu-item" href="/categories/documentation/" title="">文档</a><a class="menu-item" href="/about/" title="">关于</a><a class="menu-item" href="https://gitee.com/wuzpdev" title="Gitee" rel="noopener noreffer" target="_blank"><i class='fab fa-github fa-fw'></i></a><a href="javascript:void(0);" class="menu-item theme-switch" title="切换主题">
                <i class="fas fa-adjust fa-fw"></i>
            </a></div>
    </div>
</header>
<div class="search-dropdown desktop">
    <div id="search-dropdown-desktop"></div>
</div>
<div class="search-dropdown mobile">
    <div id="search-dropdown-mobile"></div>
</div>
<main class="main">
                <div class="container"><div class="toc" id="toc-auto">
            <h2 class="toc-title">目录</h2>
            <div class="toc-content" id="toc-content-auto"></div>
        </div><article class="page single"><h1 class="single-title animated flipInX">Makefile</h1><div class="post-meta">
            <div class="post-meta-line"><span class="post-author"><a href="/" title="Author" rel=" author" class="author"><i class="fas fa-user-circle fa-fw"></i>wuzp</a></span>&nbsp;<span class="post-category">收录于 <a href="/categories/linux/"><i class="far fa-folder fa-fw"></i>Linux</a></span></div>
            <div class="post-meta-line"><i class="far fa-calendar-alt fa-fw"></i>&nbsp;<time datetime="2022-01-25">2022-01-25</time>&nbsp;<i class="fas fa-pencil-alt fa-fw"></i>&nbsp;约 7281 字&nbsp;
                <i class="far fa-clock fa-fw"></i>&nbsp;预计阅读 15 分钟&nbsp;</div>
        </div><div class="featured-image"><img
        class="lazyload"
        src="/svg/loading.min.svg"
        data-src="images/Tulips.jpg"
        data-srcset="/images/Tulips.jpg, images/Tulips.jpg 1.5x, /images/Tulips.jpg 2x"
        data-sizes="auto"
        alt="/images/Tulips.jpg"
        title="/images/Tulips.jpg" /></div><div class="details toc" id="toc-static"  kept="">
                <div class="details-summary toc-title">
                    <span>目录</span>
                    <span><i class="details-icon fas fa-angle-right"></i></span>
                </div>
                <div class="details-content toc-content" id="toc-content-static"><nav id="TableOfContents">
  <ul>
    <li><a href="#工作方式">工作方式</a></li>
    <li><a href="#规则">规则</a></li>
    <li><a href="#文件搜索">文件搜索</a></li>
    <li><a href="#伪目标">伪目标</a></li>
    <li><a href="#静态模式">静态模式</a></li>
    <li><a href="#命令">命令</a>
      <ul>
        <li><a href="#显示命令">显示命令</a></li>
        <li><a href="#命令出错">命令出错</a></li>
        <li><a href="#定义命令包">定义命令包</a></li>
      </ul>
    </li>
    <li><a href="#使用变量">使用变量</a>
      <ul>
        <li><a href="#变量的基础">变量的基础</a></li>
        <li><a href="#高级用法">高级用法</a></li>
        <li><a href="#override-指示符">override 指示符</a></li>
        <li><a href="#目标变量">目标变量</a></li>
        <li><a href="#模式变量">模式变量</a></li>
      </ul>
    </li>
    <li><a href="#条件判断">条件判断</a></li>
    <li><a href="#函数">函数</a>
      <ul>
        <li><a href="#字符串处理函数">字符串处理函数</a></li>
        <li><a href="#文件名操作函数">文件名操作函数</a></li>
        <li><a href="#foreach-函数">foreach 函数</a></li>
        <li><a href="#if-函数">if 函数</a></li>
        <li><a href="#call-函数">call 函数</a></li>
        <li><a href="#origin-函数">origin 函数</a></li>
        <li><a href="#shell-函数">shell 函数</a></li>
        <li><a href="#控制make的函数">控制make的函数</a></li>
      </ul>
    </li>
    <li><a href="#make的运行">make的运行</a></li>
    <li><a href="#隐含规则">隐含规则</a>
      <ul>
        <li><a href="#隐含规则中的命令变量以及命令参数的变量">隐含规则中的命令变量以及命令参数的变量</a></li>
        <li><a href="#自动化变量">自动化变量</a></li>
      </ul>
    </li>
    <li><a href="#函数库文件静态库或动态库">函数库文件(静态库或动态库)</a></li>
  </ul>
</nav></div>
            </div><div class="content" id="content"><h2 id="工作方式">工作方式</h2>
<p>GNU的make工作时的执行步骤如下：</p>
<ol>
<li>读入所有的Makefile.</li>
<li>读入被include的其他Makefile</li>
<li>初始化文件中的变量</li>
<li>推导隐晦规则，并分析所有规则</li>
<li>为所有的目标文件创建依赖关系链</li>
<li>根据依赖关系，决定哪些目标要重新生成</li>
<li>执行生成命令</li>
</ol>
<p>1-5步为第一个阶段，6-7为第二个阶段。第一个阶段中，如果定义的变量被使用了，那么make会把其展开在使用的位置。
但make并不会完全马上展开，make使用的是拖延战术，如果变量出现在依赖关系的规则中，那么仅当这条依赖被决定要使用了，变量才会在其内部展开。</p>
<h2 id="规则">规则</h2>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell">targets ... : prerequisties ...
    <span class="nb">command</span>
    ...
    ...
</code></pre></td></tr></table>
</div>
</div><p>targets: 可以是一个object file(目标文件)，也可以是一个执行文件，还可以是一个标签(label)(伪目标)
prerequisties: 生成target所依赖的文件或target
commond: 生成target所要执行的命令(任意shell命令),该命令要以Tab键开头</p>
<p>规则包含两个部分，一个是依赖关系，一个是生成目标的方法。
在Makefile中，规则的顺序是很重要的，因为，Makefile中只应该有一个最终目标，其他的目标都是被这个目标所连带出来的，所以一定要让make知道最终目标是什么。一般来说，定义在Makefile中的目标可能有很多，但是第一条规则中的额目标将被确立为最终目标。如果第一条规则中的目标有很多个，那么，第一个目标会成为最终的目标。</p>
<h2 id="文件搜索">文件搜索</h2>
<p>Makefile文件中的特殊变量VPATH可以自动找寻文件的依赖关系，如果没有指明这个变量，make只会在当前的目录中取找寻依赖文件和目标文件。如果定义了这个变量，那么，make就会在当前目录找不到的情况下，到所指定的目录中去找寻文件</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="nv">VPATH</span> <span class="o">=</span> src:../headers
</code></pre></td></tr></table>
</div>
</div><p>上面的定义指定了两个目录，&ldquo;src&quot;和&rdquo;../headers&quot;，make会按照这个顺序进行搜索。目录由冒号分隔</p>
<p>另一个设置文件搜索路径的方法是使用make的&quot;vpath&quot;关键字(注意，它是全小写的)，这不是变量，这是一个make的关键字，这和上面的VPATH变量类似，但是它更为灵活.它可以指定不同文件在不同的搜索目录中。它的使用方法有三种:</p>
<ol>
<li>vpath <pattern> <directories>    为符合模式<pattern>的文件指定搜索目录<directories>,目录以冒号分隔</li>
<li>vpath <pattern>                  清除符合模式<pattern>的文件的搜索目录</li>
<li>vpath                            清除所有已被设置好了的文件搜索目录</li>
</ol>
<p>vpath使用方法中的<pattern>需要包含%符号。%的意思是匹配零或若干个字符。</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell">vpath %.c foo:bar
vpath % blish
</code></pre></td></tr></table>
</div>
</div><p>上面语句表示.c结尾的文件，先在&quot;foo&quot;目录，然后在&quot;bar&quot;目录，最后才是&quot;blish&quot;目录搜索</p>
<h2 id="伪目标">伪目标</h2>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell">clean:
    rm *.o tmp
</code></pre></td></tr></table>
</div>
</div><p>伪目标clean并不是一个文件，只是一个标签，由于&quot;伪目标&quot;不是文件，所有make无法生成它的依赖关系和决定是否要执行。只有通过显式地指明这个&quot;目标&quot;才能让其生效。&ldquo;伪目标&quot;的取名不能和文件名重名。</p>
<p>为了避免和文件重名，可以使用一个特殊的标记&rdquo;.PHONY&quot;来显式地指明一个目标是&quot;伪目标&quot;,向make说明，不管是否有这个文件，这个目标就是&quot;伪目标&quot;.</p>
<p>伪目标一般是没有依赖的文件，但是，也可以为伪目标指定所依赖的文件，由于伪目标不会生成文件，因此所依赖的文件总是会被执行。因此可以利用伪目标一口气生成若干个可执行文件。
伪目标可以作为默认目标</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell">all : prog1 prog2 prog3
.PHONY : all

prog1 : prog1.o utils.o
    cc -o prog1 prog1.o utils.o
    
prog2 : prog2.o utils.o
    cc -o prog2 prog2.o utils.o
    
prog3 : prog3.o utills.o
    cc -o prog3 prog3.o utils.o

</code></pre></td></tr></table>
</div>
</div><h2 id="静态模式">静态模式</h2>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell">&lt;targets ...&gt; : &lt;target-pattern&gt; : &lt;prereq-patterns ...&gt;
    &lt;commands&gt;
    ...
</code></pre></td></tr></table>
</div>
</div><p>targets : 定义了一系列的目标文件，可以有通配符，是目标的一个集合,集合中的所有元素都要匹配target-pattern模式，如果不匹配，可以使用filter函数过滤
target-pattern : 指明了targets的模式，也就是目标集模式
prereq-patterns : 目标的依赖模式，它对target-pattern形成的模式再进行一次依赖目标的定义</p>
<p>如果target-pattern定义成%.o,而prereq-patterns定义成%.c, 意思是<target>集合中以.o结尾的目标，依赖于&lt;target_pattern&gt;模式中的%，并为其加上.c这个结尾的文件集合。</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span><span class="lnt">6
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="nv">objects</span> <span class="o">=</span> foo.o bar.o 

all : <span class="k">$(</span>objects<span class="k">)</span>

<span class="k">$(</span>objects<span class="k">)</span> : %.o : %.c
    <span class="k">$(</span>CC<span class="k">)</span> -c <span class="k">$(</span>CFLAGS<span class="k">)</span> $&lt; -o %@
</code></pre></td></tr></table>
</div>
</div><p>上面的例子中，指明了我们的目标从 $object 中获取，%.o 表明要所有以 .o 结尾的目标，也就是foo.o bar.o ，也就是变量 $object 集合的模式，
而依赖模式 %.c 则取模式 %.o 的 % ，也就是 foo bar，并为其加下 .c 的后缀，于是，我们的依赖目标就是 foo.c bar.c 。
而命令中的 $&lt; 和 $@ 则是自动化变量，$&lt; 表示第一个依赖文件，$@ 表示目标集（也就是“foo.o bar.o”）</p>
<h2 id="命令">命令</h2>
<p>每条规则中的命令和操作系统shell的命令行是一致的。make会按顺序一条一条的执行命令，每条命令的开头必须以Tab键开头</p>
<h3 id="显示命令">显示命令</h3>
<p>通常，make会把其要执行的命令行在命令执行前输出到屏幕上，当用@字符在命令行前，那么这个命令不被make显示出来。</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell">@echo 正在编译 XXX 模块……
</code></pre></td></tr></table>
</div>
</div><p>当 make 执行时，会输出“正在编译 XXX 模块……”字串，但不会输出命令，如果没有“@”，那么，make 将输出</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell">@echo 正在编译 XXX 模块……
正在编译 XXX 模块……
</code></pre></td></tr></table>
</div>
</div><p>如果 make 执行时，带入 make 参数 -n 或 &ndash;just-print ，那么其只是显示命令，但不会执行命令，这个功能很有利于我们调试我们的 Makefile，看看我们书写的命令是执行起来是什么样子的或是什么顺序的。
而 make 参数 -s 或 &ndash;silent 或 &ndash;quiet 则是全面禁止命令的显示.</p>
<h3 id="命令出错">命令出错</h3>
<p>每当命令运行完后，make会检测每个命令的返回码，如果命令返回成功，那么make会执行下一条命令，当规则中所有的命令成功返回后，这个规则算是成功完成了。如果一个规则中的某个命令出错了(命令退出码非零)，那么make就会终止执行当前规则，这将有可能终止所有规则的执行。</p>
<p>为了做到忽略命令的出错，可以在Makefile的命令行前加一个减号-(在Tab键之后)，标记为不管命令出不出错都认为是成功的。</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell">clean:
    -rm -f *.o
</code></pre></td></tr></table>
</div>
</div><h3 id="定义命令包">定义命令包</h3>
<p>如果Makefile中出现一些相同命令序列，那么可以为这些相同的命令序列定义一个变量。定义这种命令序列的语法以define开始，以endef结束</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell">define run-yacc
yacc <span class="k">$(</span>firstword $^<span class="k">)</span>
mv y.tab.c <span class="nv">$@</span>
endef
</code></pre></td></tr></table>
</div>
</div><h2 id="使用变量">使用变量</h2>
<p>在Makefile中定义的变量，就像是c/c++语言中的宏一样，代表一个文本字串，在Makefile中执行的时候其会自动原模原样地展开在所使用的地方。变量是大小写敏感的。
但是要注意，<strong>==在变量定义的时候要注意结尾的空格，不然可能会导致意想不到的结果==</strong></p>
<h3 id="变量的基础">变量的基础</h3>
<p>变量在声明时需要给予初值，而在使用时，需要给变量名前加上$符号，但最好用小括号()或大括号{}把变量包括起来，如果要使用真实的$字符，需要使用$$来表示</p>
<p>变量定义的几种方式：</p>
<ol>
<li>= : 使用&quot;=&ldquo;赋值，变量的值是整个makefile中最后被指定的值</li>
<li>:= : 表示直接赋值，赋予当前位置的值，不会随变量在其后改变而改变</li>
<li>?= : 如果该变量没有被赋值，则赋予等号后的值</li>
<li>+= : 将等号后面的值添加到前面的变量上</li>
</ol>
<h3 id="高级用法">高级用法</h3>
<ol>
<li>变量值的替换</li>
</ol>
<p>替换变量中的共有的部分，其格式是$(var:a=b)或是${var:a=b},其意思是，把变量var中所有以a字串结尾的a替换成b字串。</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell">foo :<span class="o">=</span> a.o b.o c.o
bar :<span class="o">=</span> <span class="k">$(</span>foo:.o<span class="o">=</span>.c<span class="k">)</span>
</code></pre></td></tr></table>
</div>
</div><div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell">foo :<span class="o">=</span> a.o b.o c.o
bar :<span class="o">=</span> <span class="k">$(</span>foo:%.o<span class="o">=</span>%.c<span class="k">)</span>
</code></pre></td></tr></table>
</div>
</div><ol start="2">
<li>把变量的值再当成变量</li>
</ol>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="nv">x</span> <span class="o">=</span> y
<span class="nv">y</span> <span class="o">=</span> z
a :<span class="o">=</span> <span class="k">$($(</span>x<span class="k">))</span>
</code></pre></td></tr></table>
</div>
</div><p>在这个例子中，$(x) 的值是“y”，所以 $($(x)) 就是 $(y)，于是 $(a) 的值就是“z”.</p>
<h3 id="override-指示符">override 指示符</h3>
<p>如果有变量是通过make命令行参数设置的，那么Makefile中对这个变量的赋值会被忽略。如果想在Makefile中设置这类参数的值，可以使用override指示符。其语法是：</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell">override &lt;variable&gt; <span class="o">=</span> &lt;value&gt;
override &lt;variable&gt; :<span class="o">=</span> &lt;value&gt;
override &lt;variable&gt; +<span class="o">=</span> &lt;value&gt;
</code></pre></td></tr></table>
</div>
</div><p>对于多行的变量定义，用define指示符，在define指示符前，同样可以使用override指示符，</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell">override define foo
bar
endef
</code></pre></td></tr></table>
</div>
</div><h3 id="目标变量">目标变量</h3>
<p>在Makefile中定义的变量都是&quot;全局变量&rdquo;，同样可以为某个目标设置局部变量，这种变量称为&quot;target-specific variable&quot;，它可以和&quot;全局变量&quot;同名，因为它的作用范围只在这条规则以及连带规则中，所以其值也只在作用范围内有效，而不会想想规则链以外的全局变量的值。
其语法是:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell">&lt;target ...&gt; : &lt;variable-assignment&gt;
&lt;target ...&gt; : override &lt;variable-assignment&gt;
</code></pre></td></tr></table>
</div>
</div><h3 id="模式变量">模式变量</h3>
<p>模式一般是至少含有一个%的，其语法是</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell">&lt;pattern ...&gt; : &lt;variable-assignment&gt;
&lt;pattern ...&gt; : override &lt;variable-assignment&gt;
</code></pre></td></tr></table>
</div>
</div><h2 id="条件判断">条件判断</h2>
<p>语法：</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span><span class="lnt">6
</span><span class="lnt">7
</span><span class="lnt">8
</span><span class="lnt">9
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell">&lt;conditional-directive&gt;
&lt;text-if-true&gt;
endif

&lt;conditional-directive&gt;
&lt;text-if-true&gt;
<span class="k">else</span>
&lt;text-if-false&gt;
endif
</code></pre></td></tr></table>
</div>
</div><p>其中<conditional-directive>表示条件关键字，这样的关键字有四个: ifeq, ifneq, ifdef, ifndef</p>
<h2 id="函数">函数</h2>
<p>函数调用，也是用$标识的，其语法如下:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="k">$(</span>&lt;<span class="k">function</span>&gt; &lt;argument&gt;<span class="k">)</span>
<span class="si">${</span><span class="p">&lt;function&gt; &lt;argument&gt;</span><span class="si">}</span>
</code></pre></td></tr></table>
</div>
</div><p><function>是函数名，<argument>为函数的参数，参数间以逗号,分隔，而函数名和参数之间以“空格”分隔，函数调用以$开头，以圆括号或花括号把函数名和参数括起。</p>
<h3 id="字符串处理函数">字符串处理函数</h3>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span><span class="lnt">21
</span><span class="lnt">22
</span><span class="lnt">23
</span><span class="lnt">24
</span><span class="lnt">25
</span><span class="lnt">26
</span><span class="lnt">27
</span><span class="lnt">28
</span><span class="lnt">29
</span><span class="lnt">30
</span><span class="lnt">31
</span><span class="lnt">32
</span><span class="lnt">33
</span><span class="lnt">34
</span><span class="lnt">35
</span><span class="lnt">36
</span><span class="lnt">37
</span><span class="lnt">38
</span><span class="lnt">39
</span><span class="lnt">40
</span><span class="lnt">41
</span><span class="lnt">42
</span><span class="lnt">43
</span><span class="lnt">44
</span><span class="lnt">45
</span><span class="lnt">46
</span><span class="lnt">47
</span><span class="lnt">48
</span><span class="lnt">49
</span><span class="lnt">50
</span><span class="lnt">51
</span><span class="lnt">52
</span><span class="lnt">53
</span><span class="lnt">54
</span><span class="lnt">55
</span><span class="lnt">56
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell">// 字符串替换函数
// 把字串&lt;text&gt;中的&lt;from&gt;字符串替换成&lt;to&gt;
// 返回被替换过后的字符串
<span class="k">$(</span>subst &lt;from&gt;,&lt;to&gt;,&lt;text&gt;<span class="k">)</span>

// 模式字符串替换函数
// 查找&lt;text&gt;中的单词<span class="o">(</span>单词以“空格”，“Tab”或“回车”“换行”分隔<span class="o">)</span>是否符合模式&lt;pattern&gt;，如果匹配的话，则以&lt;replacement&gt;替换。这里&lt;pattern&gt;可以包括通配符%
// 表示任意长度的字串。如果&lt;replacement&gt;中也包含%。那么&lt;replacement&gt;中的这个%将是&lt;pattern&gt;中的那个%所代表的字串
// 函数返回被替换过后的字符串
<span class="k">$(</span>patsubst &lt;pattern&gt;,&lt;replacement&gt;,&lt;text&gt;<span class="k">)</span>

// 去空格函数
// 去掉&lt;string&gt;字串中开头和结尾的空字符
// 返回被去掉空格的字符串值
<span class="k">$(</span>strip &lt;string&gt;<span class="k">)</span>

// 查找字符串函数
// 在字串&lt;in&gt;中查找&lt;find&gt;字串
// 如果找到，那么返回&lt;find&gt;, 否则返回空字符串
<span class="k">$(</span>findstring &lt;from&gt;,&lt;in&gt;<span class="k">)</span>

// 过滤函数
// 以&lt;pattern&gt;模式过滤&lt;text&gt;字符串中的单词，保留符合模式&lt;pattern&gt;的单词,可以有多个模式，各模式以空格分隔
// 返回符合模式&lt;pattern&gt;的字串
<span class="k">$(</span>filter &lt;pattern...&gt;,&lt;text&gt;<span class="k">)</span>

// 反过滤函数
// 以&lt;pattern&gt;模式过滤&lt;text&gt;字符串中的单词,去除符合模式&lt;pattern&gt;的单词，可以有多个模式，各模式以空格分隔
// 返回不符合模式&lt;pattern&gt;的字串
<span class="k">$(</span>filter-out &lt;pattern...&gt;,&lt;text&gt;<span class="k">)</span>

// 排序函数
// 给字符串&lt;list&gt;中的单词排序<span class="o">(</span>升序<span class="o">)</span>
// 返回排序后的字符串,去掉相同的单词
<span class="k">$(</span>sort &lt;list&gt;<span class="k">)</span>

// 去单词函数
// 取字符串&lt;text&gt;中第&lt;n&gt;个单词,从一开始
// 返回字符串&lt;text&gt;中第&lt;n&gt;个单词，如果&lt;n&gt;比&lt;text&gt;中的单词数要大，那么返回空字符串
<span class="k">$(</span>word &lt;n&gt;,&lt;text&gt;<span class="k">)</span>

// 取单词串函数
// 从字符串&lt;text&gt;中取从&lt;ss&gt;开始到&lt;e&gt;的单词串. &lt;ss&gt;和&lt;e&gt;是一个数字
// 返回字符串&lt;text&gt;中从&lt;ss&gt;到&lt;e&gt;的单词串，如果&lt;ss&gt;比&lt;text&gt;中的单词数要大，那么返回空字符串，如果&lt;e&gt;大于&lt;text&gt;的单词数，那么返回从&lt;ss&gt;开始，到&lt;text&gt;结束的单词串
<span class="k">$(</span>wordlist &lt;ss&gt;,&lt;e&gt;,&lt;text&gt;<span class="k">)</span>

// 单词个数统计函数
// 统计&lt;text&gt;中字符串中的单词个数
// 返回&lt;text&gt;中的单词数
<span class="k">$(</span>words &lt;text&gt;<span class="k">)</span>

// 首单词函数
// 取字符串&lt;text&gt;中的第一个单词
// 返回字符串&lt;text&gt;中的第一个单词
<span class="k">$(</span>firstword &lt;text&gt;<span class="k">)</span>

</code></pre></td></tr></table>
</div>
</div><h3 id="文件名操作函数">文件名操作函数</h3>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span><span class="lnt">21
</span><span class="lnt">22
</span><span class="lnt">23
</span><span class="lnt">24
</span><span class="lnt">25
</span><span class="lnt">26
</span><span class="lnt">27
</span><span class="lnt">28
</span><span class="lnt">29
</span><span class="lnt">30
</span><span class="lnt">31
</span><span class="lnt">32
</span><span class="lnt">33
</span><span class="lnt">34
</span><span class="lnt">35
</span><span class="lnt">36
</span><span class="lnt">37
</span><span class="lnt">38
</span><span class="lnt">39
</span><span class="lnt">40
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell">// 取目录函数
// 从文件名序列&lt;names&gt;中取出目录部分，目录部分是指最后一个反斜杠<span class="o">(</span>/<span class="o">)</span>之前的部分,如果没有反斜杠,那么返回./
// 返回文件名序列&lt;names&gt;的目录部分
<span class="k">$(</span>dir &lt;names...&gt;<span class="k">)</span>

// 取文件函数
// 从文件名序列&lt;names&gt;中取出非目录部分,非目录部分是指最后一个反斜杠<span class="o">(</span>/<span class="o">)</span>之后的部分
// 返回文件名序列&lt;names&gt;的非目录部分
<span class="k">$(</span>notdir &lt;names...&gt;<span class="k">)</span>

// 取后缀函数
// 从文件名序列&lt;names&gt;中取出各个文件名的后缀
// 返回文件名序列&lt;names&gt;的后缀序列，如果文件没有后缀，则返回空字串
<span class="k">$(</span>suffix &lt;names...&gt;<span class="k">)</span>

// 取前缀函数
// 从文件名序列&lt;names&gt;中取出各个文件名的前缀部分
// 返回文件名序列&lt;names&gt;的前缀序列，如果文件没有前缀，则返回空字串
<span class="k">$(</span>basename &lt;names...&gt;<span class="k">)</span>

// 加后缀函数
// 把后缀&lt;suffix&gt;加到&lt;names&gt;中的每个单词后面
// 返回加过后缀的文件名序列
<span class="k">$(</span>addsuffix &lt;suffix&gt;,&lt;names...&gt;<span class="k">)</span>

// 加前缀函数
// 把前缀&lt;prefix&gt;加到&lt;names&gt;中的每个单词前面
// 返回加过前缀的文件名序列
<span class="k">$(</span>addprefix &lt;prefix&gt;,&lt;names...&gt;<span class="k">)</span>

// 连接函数
// 把&lt;list2&gt;中的单词对应地加到&lt;list1&gt;的单词后面，如果&lt;list1&gt;的单词个数要比&lt;list2&gt;的多，那么&lt;list1&gt;中多出来的单词将保持原样。如果&lt;list2&gt;的单词个数要比&lt;list1&gt;多，那么&lt;list2&gt;多出来的单词将被复制到&lt;list1&gt;中
// 返回连接后的字符串
<span class="k">$(</span>join &lt;list1&gt;,&lt;list2&gt;<span class="k">)</span>
如: <span class="k">$(</span>join aaa bbb, <span class="m">111</span> <span class="m">222</span> 333<span class="k">)</span> 返回值是 aaa111 bbb222 <span class="m">333</span>

// 扩展通配符
// 展开为已经存在的、使用空格分开的、匹配此模式的所有文件列表。如果不存在任何符合此模式的文件，函数会忽略模式字符并返回空
// 该模式中的为linux系统中的通配符
<span class="k">$(</span>wildcard &lt;pattern...&gt;<span class="k">)</span>
</code></pre></td></tr></table>
</div>
</div><h3 id="foreach-函数">foreach 函数</h3>
<p>语法:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="k">$(</span>foreach &lt;var&gt;,&lt;list&gt;,&lt;text&gt;<span class="k">)</span>
</code></pre></td></tr></table>
</div>
</div><p>把参数<list>中的单词逐一取出放到参数<var>所指定的变量中，然后再执行<text>所包含的表达式.每一次<text>会返回一个字符串，循环过程中，<text>的所返回的每个字符串会以空格分隔，最后当整个循环结束时，<text>所返回的每个字符串所组成的整个字符串(以空格分隔)将会是foreach函数的返回值。</p>
<h3 id="if-函数">if 函数</h3>
<p>语法:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="k">$(if</span> &lt;condition&gt;,&lt;<span class="k">then</span>-part&gt;<span class="k">)</span>
<span class="k">$(if</span> &lt;condition&gt;,&lt;<span class="k">then</span>-part&gt;,&lt;elst-part&gt;<span class="k">)</span>
</code></pre></td></tr></table>
</div>
</div><h3 id="call-函数">call 函数</h3>
<p>语法:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="k">$(</span>call &lt;expression&gt;,&lt;param1&gt;,&lt;param2&gt;,...,&lt;paramn&gt;<span class="k">)</span>
</code></pre></td></tr></table>
</div>
</div><p>当make执行这个函数时，<expression>参数中的变量, 如$(1),$(2)等，会被参数<param1>,<param2>,<param3>依次取代.而<expression>的返回值就是call函数的返回值。
需要注意: 在向call函数传递参数时要尤其注意空格的使用，call函数在处理参数时，第2个及其之后的参数中的空格会被保留，因而可能造成一些奇怪的效果。因而在向call函数提供参数时，最安全的做法是去除所有多余的空格。即<param1>,<param2>,&hellip;,<paramn>==各个参数前不能有空格==</p>
<h3 id="origin-函数">origin 函数</h3>
<p>语法:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="k">$(</span>origin &lt;variable&gt;<span class="k">)</span>
</code></pre></td></tr></table>
</div>
</div><p>注意，<variable>是变量的名字，不应该是引用，所以最好不要在<variable>中使用$字符.</p>
<p>返回值:</p>
<ol>
<li>undefined: <variable>从来没有定义过</li>
<li>default: <variable>是一个默认的定义,比如&quot;CC&quot; 这个变量</li>
<li>environment: <variable>是一个环境变量，并且当Makefile被执行时，-e参数没有被打开</li>
<li>file: <variable>被定义在Makefile中</li>
<li>commond line: <variable>这个变量被命令行定义</li>
<li>override: <variable>是被override指示符重新定义的</li>
<li>automatic: <variable>是一个命令运行中的自动化变量</li>
</ol>
<h3 id="shell-函数">shell 函数</h3>
<p>shell函数把执行操作系统命令后的输出作为函数的返回,和反引号&quot;`&ldquo;是相同的功能</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell">contents :<span class="o">=</span> <span class="k">$(</span>shell cat foo<span class="k">)</span>
</code></pre></td></tr></table>
</div>
</div><p>注意，这个函数会新生成一个shell程序来执行命令，所以要注意其运行性能。</p>
<h3 id="控制make的函数">控制make的函数</h3>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="k">$(</span>error &lt;text ...&gt;<span class="k">)</span>
<span class="k">$(</span>warning &lt;text ...&gt;<span class="k">)</span>
</code></pre></td></tr></table>
</div>
</div><h2 id="make的运行">make的运行</h2>
<p>make命令执行后有三个退出码:
0: 表示成功执行
1: 如果make运行时出现任何错误，其返回1
2: 如果使用了make的&rdquo;-q&quot;选项，并且make使得一些目标不需要更新，那么返回2</p>
<p>常用目标：</p>
<ol>
<li>all : 这个伪目标是所有目标的目标，其功能一般是编译所有的目标</li>
<li>clean : 这个伪目标功能是删除所有被make创建的文件</li>
<li>install : 这个伪目标功能是安装已编译函的程序，其实就是把目标执行文件拷贝到指定的目标中去</li>
<li>print : 这个伪目标的功能是列出改变过的源文件</li>
<li>tar : 这个伪目标功能是把源程序打包备份，也就是一个tar文件</li>
<li>dist : 这个伪目标功能是创建一个压缩文件，一般是把tar文件压成Z文件或者gz文件</li>
<li>TAGS : 这个伪目标功能是更新所有的目标，以备完整地重新编译使用</li>
<li>check和test: 这两个伪目标一般用来测试makefile的流程</li>
</ol>
<h2 id="隐含规则">隐含规则</h2>
<h3 id="隐含规则中的命令变量以及命令参数的变量">隐含规则中的命令变量以及命令参数的变量</h3>
<ul>
<li>AR: 函数库打包程序,默认命令是ar</li>
<li>CC: C语言编译程序,默认命令时cc</li>
<li>CXX: C++语言编译程序,默认命令时g++</li>
<li>ARFLAGS: 函数库打包程序AR命令的参数, 默认值rv</li>
<li>CFLAGS: C语言编译器参数</li>
<li>CXXFLAGS: C++语言编译器参数</li>
</ul>
<h3 id="自动化变量">自动化变量</h3>
<ul>
<li>$@ : 表示规则中的目标文件集。在模式规则中，如果有多个目标，那么，$@就是匹配于目标中模式定义的集合</li>
<li>$% : 仅当目标是函数库文件(静态库或动态库),表示规则中的目标成员名。例如，如果一个目标是foo.a(bar.o),那么，$%就是bar.o，$@就是foo.a。如果目标不是函数库文件，那么其值为空</li>
<li>$&lt; : 依赖目标中的第一个目标名字。如果依赖目标是以模式(即%)定义的，那么$&lt;将是符合模式的一系列的文件，注意，其是一个一个取出来的。</li>
<li>$? : 所有比目标新的依赖目标的集合。以空格分隔</li>
<li>$^ : 所有的依赖目标的集合，以空格分隔，如果在依赖目标中有多个重复的，那么这个变量会去除重复的依赖目标，只保留一份。</li>
<li>$+ : 类似$^, 也是所有依赖目标的集合，只是它不去除重复的依赖目标</li>
<li>$* : 这个变量表示目标模式中%及其之前的部分。如果目标是dir/a.foo.b,并且目标的模式是a.%.b，那么$*的值就是dir/a.foo.如果目标中没有模式的定义，那么$*也就不能被推导出来。但是，如果目标文件的后缀是make所识别的，那么$*就是除了后缀的那一部分。如果目标中的后缀是make所不能识别的，那么$*就是空值</li>
</ul>
<h2 id="函数库文件静态库或动态库">函数库文件(静态库或动态库)</h2>
<p>一个函数库文件由多个文件组成，其格式如下</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell">archive<span class="o">(</span>member<span class="o">)</span>
</code></pre></td></tr></table>
</div>
</div><p>以上笔记来自《跟我一起写Makefile》 陈皓</p>
</div><div class="post-footer" id="post-footer">
    <div class="post-info">
        <div class="post-info-line">
            <div class="post-info-mod">
                <span>更新于 2022-01-25</span>
            </div>
            <div class="post-info-license"></div>
        </div>
        <div class="post-info-line">
            <div class="post-info-md"></div>
            <div class="post-info-share">
                <span><a href="javascript:void(0);" title="分享到 Twitter" data-sharer="twitter" data-url="https://wuzpdev.gitee.io/makefile/" data-title="Makefile" data-hashtags="makefile"><i class="fab fa-twitter fa-fw"></i></a><a href="javascript:void(0);" title="分享到 Facebook" data-sharer="facebook" data-url="https://wuzpdev.gitee.io/makefile/" data-hashtag="makefile"><i class="fab fa-facebook-square fa-fw"></i></a><a href="javascript:void(0);" title="分享到 微博" data-sharer="weibo" data-url="https://wuzpdev.gitee.io/makefile/" data-title="Makefile" data-image="images/Tulips.jpg" data-ralateuid="xxxx"><i class="fab fa-weibo fa-fw"></i></a><a href="javascript:void(0);" title="分享到 人人" data-sharer="renren" data-url="https://wuzpdev.gitee.io/makefile/"><i class="fab fa-renren fa-fw"></i></a><a href="javascript:void(0);" title="分享到 Myspace" data-sharer="myspace" data-url="https://wuzpdev.gitee.io/makefile/" data-title="Makefile" data-description=""><i data-svg-src="https://cdn.jsdelivr.net/npm/simple-icons@2.14.0/icons/myspace.svg"></i></a><a href="javascript:void(0);" title="分享到 Blogger" data-sharer="blogger" data-url="https://wuzpdev.gitee.io/makefile/" data-title="Makefile" data-description=""><i class="fab fa-blogger fa-fw"></i></a></span>
            </div>
        </div>
    </div>

    <div class="post-info-more">
        <section class="post-tags"><i class="fas fa-tags fa-fw"></i>&nbsp;<a href="/tags/makefile/">makefile</a></section>
        <section>
            <span><a href="javascript:void(0);" onclick="window.history.back();">返回</a></span>&nbsp;|&nbsp;<span><a href="/">主页</a></span>
        </section>
    </div>

    <div class="post-nav"><a href="/cmake/" class="prev" rel="prev" title="CMake"><i class="fas fa-angle-left fa-fw"></i>CMake</a></div>
</div>
</article></div>
            </main><footer class="footer">
        <div class="footer-container"><div class="footer-line"><i class="far fa-copyright fa-fw"></i><span itemprop="copyrightYear">2019 - 2022</span><span class="author" itemprop="copyrightHolder">&nbsp;<a href="/" target="_blank">wuzp</a></span>&nbsp;|&nbsp;<span class="license"><a rel="license external nofollow noopener noreffer" href="https://creativecommons.org/licenses/by-nc/4.0/" target="_blank">CC BY-NC 4.0</a></span></div>
        </div>
    </footer></div>

        <div id="fixed-buttons"><a href="#" id="back-to-top" class="fixed-button" title="回到顶部">
                <i class="fas fa-arrow-up fa-fw"></i>
            </a><a href="#" id="view-comments" class="fixed-button" title="查看评论">
                <i class="fas fa-comment fa-fw"></i>
            </a>
        </div><script type="text/javascript" src="https://cdn.jsdelivr.net/npm/smooth-scroll@16.1.3/dist/smooth-scroll.min.js"></script><script type="text/javascript" src="https://cdn.jsdelivr.net/npm/autocomplete.js@0.37.1/dist/autocomplete.min.js"></script><script type="text/javascript" src="https://cdn.jsdelivr.net/npm/algoliasearch@4.2.0/dist/algoliasearch-lite.umd.min.js"></script><script type="text/javascript" src="https://cdn.jsdelivr.net/npm/lazysizes@5.2.2/lazysizes.min.js"></script><script type="text/javascript" src="https://cdn.jsdelivr.net/npm/clipboard@2.0.6/dist/clipboard.min.js"></script><script type="text/javascript" src="https://cdn.jsdelivr.net/npm/sharer.js@0.4.0/sharer.min.js"></script><script type="text/javascript">window.config={"code":{"copyTitle":"复制到剪贴板","maxShownLines":10},"comment":{},"search":{"algoliaAppID":"PASDMWALPK","algoliaIndex":"index.zh-cn","algoliaSearchKey":"b42948e51daaa93df92381c8e2ac0f93","highlightTag":"em","maxResultLength":10,"noResultsFound":"没有找到结果","snippetLength":50,"type":"algolia"}};</script><script type="text/javascript" src="/js/theme.min.js"></script></body>
</html>
